package com.zmx.oauth2.utils;

import com.zmx.common.common.exception.BusinessException;
import org.springframework.util.Assert;

import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.xml.bind.DatatypeConverter;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

/**
 * @Description: 基于PBKDF2密码加密，验证
 * @ClassName: PBKDF2Util
 * @Author zhaomxr
 * @Date 2021-11-05 16:55
 */
public class PBKDF2Util {

    public static final String PBKDF2_ALGORITHM = "PBKDF2WithHmacSHA1";

    //盐的长度
    public static final int SALT_SIZE = 16;

    //生成密文的长度
    public static final int HASH_SIZE = 32;

    // 迭代次数
    public static final int PBKDF2_ITERATIONS = 1000;

    /**
     * 对输入的密码进行验证
     * password 密码明文
     * dataPassWord 密码加密
     */
    public static boolean verify(String password, String dataPassWord)
            throws NoSuchAlgorithmException, InvalidKeySpecException {
        Assert.notNull(password, "密码明文为空");
        Assert.notNull(dataPassWord, "密码密文为空");

        // 用相同的盐值对用户输入的密码进行加密
        String result = getPBKDF2(password, dataPassWord.substring(0, SALT_SIZE));
        // 把加密后的密文和原密文进行比较，相同则验证成功，否则失败
        return result.equals(dataPassWord.substring(SALT_SIZE, dataPassWord.length()));
    }

    /**
     * 根据password和salt生成密文
     */
    public static String getPBKDF2(String password, String salt) throws NoSuchAlgorithmException,
            InvalidKeySpecException {
        //将16进制字符串形式的salt转换成byte数组
        byte[] bytes = DatatypeConverter.parseHexBinary(salt);
        KeySpec spec = new PBEKeySpec(password.toCharArray(), bytes, PBKDF2_ITERATIONS, HASH_SIZE * 4);
        SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(PBKDF2_ALGORITHM);
        byte[] hash = secretKeyFactory.generateSecret(spec).getEncoded();
        //将byte数组转换为16进制的字符串
        return DatatypeConverter.printHexBinary(hash);
    }


    /**
     * 生成随机盐值
     */
    public static String getSalt() throws NoSuchAlgorithmException {
        SecureRandom random = SecureRandom.getInstance("SHA1PRNG");
        byte[] bytes = new byte[SALT_SIZE / 2];
        random.nextBytes(bytes);
        //将byte数组转换为16进制的字符串
        String salt = DatatypeConverter.printHexBinary(bytes);
        return salt;
    }

    /**
     * 明文密码加密
     * @param password 明文密码
     * @return 密文密码
     */
    public static String createPassWordByPBKDF2(String password) {
        try {
            return getPBKDF2(password, getSalt());
        } catch (Exception e) {
            throw new BusinessException("明文密码加密失败！", e);
        }
    }

    public static void main(String[] args) {
        try {
            String salt = getSalt();
            System.out.println("salt:" + salt);//获取salt
            String miwen = getPBKDF2("111", salt); //明文密码加密
            System.out.println("miwen:" + miwen);
            System.out.println(salt + miwen);
            System.out.println(verify("111", salt + miwen));//解密


        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
